package com.conan.dailyflickr.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;

public class BitmapUtils {

	private static final int UNCONSTRAINED = -1;
	private static final boolean ENABLE_LOG = true;
	private static final String TAG = "BitmapUtils";

	
	public void saveToSDCard(Context context, Bitmap bitmap, String name, String nam) {
	    boolean mExternalStorageAvailable = false;
	    boolean mExternalStorageWriteable = false;
	    String state = Environment.getExternalStorageState();
	    if (Environment.MEDIA_MOUNTED.equals(state)) {
	        mExternalStorageAvailable = mExternalStorageWriteable = true;
	        Log.v(TAG, "SD Card is available for read and write "
	                + mExternalStorageAvailable + mExternalStorageWriteable);
	        saveFile(context, bitmap, name, nam);
	    } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
	        mExternalStorageAvailable = true;
	        mExternalStorageWriteable = false;
	        Log.v(TAG, "SD Card is available for read "
	                + mExternalStorageAvailable);
	    } else {
	        mExternalStorageAvailable = mExternalStorageWriteable = false;
	        Log.v(TAG, "Please insert a SD Card to save your Video "
	                + mExternalStorageAvailable + mExternalStorageWriteable);
	    }
	}

	private void saveFile(Context context, Bitmap bitmap, String fullname, String nam) {

	    ContentValues values = new ContentValues();

	    File outputFile = new File(fullname);
	    values.put(MediaStore.MediaColumns.DATA, outputFile.toString());
	    values.put(MediaStore.MediaColumns.TITLE, nam);
	    values.put(MediaStore.MediaColumns.DATE_ADDED, System
	            .currentTimeMillis());
	    values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
	    Uri uri = context.getContentResolver().insert(
	            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,

	            values);;

	    try {
	        OutputStream outStream = context.getContentResolver()
	                .openOutputStream(uri);
	        bitmap.compress(Bitmap.CompressFormat.JPEG, 95, outStream);

	        outStream.flush();
	        outStream.close();
	    } catch (FileNotFoundException e) {
	        e.printStackTrace();
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	    bitmap.recycle();
	}
	
	public static Bitmap compressToMiniThumbnail(Bitmap source,
			boolean needRecycleSource) {
		return compressToMiniThumbnail(source, needRecycleSource, 96);
	}

	public static Bitmap compressToMiniThumbnail(Bitmap source,
			boolean needRecycleSource, int size) {
		if (source == null)
			return null;

		Log.d(TAG, "w=" + source.getWidth() + "  h=" + source.getHeight());

		int MINI_THUMB_TARGET_SIZE = size;

		if (source.getWidth() < size || source.getHeight() < size)
			return source;

		float scale;
		if (source.getWidth() < source.getHeight()) {
			scale = MINI_THUMB_TARGET_SIZE / source.getWidth();
		} else {
			scale = MINI_THUMB_TARGET_SIZE / source.getHeight();
		}
		Matrix matrix = new Matrix();
		matrix.setScale(scale, scale);
		Bitmap miniThumbnail = transform(matrix, source,
				MINI_THUMB_TARGET_SIZE, MINI_THUMB_TARGET_SIZE, false);
		if (needRecycleSource) {
			source.recycle();
		}

		return miniThumbnail;
	}

	public static synchronized Bitmap transform(Matrix scaler, Bitmap source,
			int targetWidth, int targetHeight, boolean scaleUp) {
		return transform(scaler, source, targetWidth, targetHeight, scaleUp,
				Bitmap.Config.RGB_565);
	}

	public static synchronized Bitmap transform(Matrix scaler, Bitmap source,
			int targetWidth, int targetHeight, boolean scaleUp,
			Bitmap.Config config) {
		if (config == null) {
			config = Bitmap.Config.RGB_565;
		}
		Log.d(TAG, "source " + source.getWidth() + " " + source.getHeight());
		int deltaX = source.getWidth() - targetWidth;
		int deltaY = source.getHeight() - targetHeight;
		Log.d(TAG, "deltaX " + deltaX + " deltaY " + deltaY);
		if ((!scaleUp) && ((deltaX < 0) || (deltaY < 0))) {
			Bitmap b2 = null;
			try {
				b2 = Bitmap.createBitmap(targetWidth, targetHeight, config);
			} catch (OutOfMemoryError oome) {
				Log.e(TAG, "memory is not enough to alloc bitmap", oome);
				return null;
			}
			Canvas c = new Canvas(b2);

			int deltaXHalf = Math.max(0, deltaX / 2);
			int deltaYHalf = Math.max(0, deltaY / 2);
			Rect src = new Rect(deltaXHalf, deltaYHalf, deltaXHalf
					+ Math.min(targetWidth, source.getWidth()), deltaYHalf
					+ Math.min(targetHeight, source.getHeight()));

			Rect dst = new Rect(0, 0, targetWidth, targetHeight);
			c.drawBitmap(source, src, dst, null);
			return b2;
		}
		float bitmapWidthF = source.getWidth();
		float bitmapHeightF = source.getHeight();

		float bitmapAspect = bitmapWidthF / bitmapHeightF;
		float viewAspect = targetWidth / targetHeight;

		if (bitmapAspect > viewAspect) {
			float scale = targetHeight / bitmapHeightF;
			if ((scale < 0.9F) || (scale > 1.0F))
				scaler.setScale(scale, scale);
			else
				scaler = null;
		} else {
			float scale = targetWidth / bitmapWidthF;
			if ((scale < 0.9F) || (scale > 1.0F))
				scaler.setScale(scale, scale);
			else
				scaler = null;
		}
		Bitmap b1;
		if (scaler != null) {
			try {
				b1 = Bitmap.createBitmap(source, 0, 0, source.getWidth(),
						source.getHeight(), scaler, true);
			} catch (OutOfMemoryError oome) {
				Log.e(TAG, "out of memory when create scaler one", oome);
				return null;
			}
		} else
			b1 = source;

		Log.d(TAG, "b1 " + b1.getWidth() + " " + b1.getHeight());
		int dx1 = Math.max(0, b1.getWidth() - targetWidth);
		int dy1 = Math.max(0, b1.getHeight() - targetHeight);

		Bitmap b2 = null;
		try {
			b2 = Bitmap.createBitmap(b1, dx1 / 2, dy1 / 2, targetWidth,
					targetHeight);
		} catch (OutOfMemoryError oome) {
			Log.e(TAG, "final tune image in transform cause oome", oome);
		}

		if (b1 != source) {
			b1.recycle();
		}
		return b2;
	}
//
//	/**
//	 * Compute the sample size as a function of minSideLength and
//	 * maxNumOfPixels. minSideLength is used to specify that minimal width or
//	 * height of a bitmap. maxNumOfPixels is used to specify the maximal size in
//	 * pixels that is tolerable in terms of memory usage.
//	 * 
//	 * The function returns a sample size based on the constraints. Both size
//	 * and minSideLength can be passed in as IImage.UNCONSTRAINED, which
//	 * indicates no care of the corresponding constraint. The functions prefers
//	 * returning a sample size that generates a smaller bitmap, unless
//	 * minSideLength = IImage.UNCONSTRAINED.
//	 * 
//	 * Also, the function rounds up the sample size to a power of 2 or multiple
//	 * of 8 because BitmapFactory only honors sample size this way. For example,
//	 * BitmapFactory downsamples an image by 2 even though the request is 3. So
//	 * we round up the sample size to avoid OOM.
//	 */
//	public static int computeSampleSize(byte[] byteIn, int maxResolutionX,
//			int maxResolutionY) {
//		BitmapFactory.Options options = new BitmapFactory.Options();
//		options.inJustDecodeBounds = true;
//		// BitmapFactory.decodeStream(stream, null, options);
//		// BitmapFactory.decodeFile(byteIn, options);
//		BitmapFactory.decodeByteArray(byteIn, 0, byteIn.length);
//		if (ENABLE_LOG) {
//			Log.i(TAG, "org bitmap width=" + options.outWidth);
//		}
//		int maxNumOfPixels = maxResolutionX * maxResolutionY;
//		int minSideLength = Math.min(maxResolutionX, maxResolutionY) / 2;
//		return computeSampleSize(options, minSideLength, maxNumOfPixels);
//	}
//
//	public static int computeSampleSize(FileInputStream input,
//			int maxResolutionX, int maxResolutionY) {
//		BitmapFactory.Options options = new BitmapFactory.Options();
//		options.inJustDecodeBounds = true;
//		// BitmapFactory.decodeStream(stream, null, options);
//		// BitmapFactory.decodeFile(byteIn, options);
//		BitmapFactory.decodeStream(input, null, options);
//		if (ENABLE_LOG) {
//			Log.i(TAG, "org bitmap width=" + options.outWidth);
//		}
//		int maxNumOfPixels = maxResolutionX * maxResolutionY;
//		int minSideLength = Math.min(maxResolutionX, maxResolutionY) / 2;
//		return computeSampleSize(options, minSideLength, maxNumOfPixels);
//	}
//
//	public static Bitmap getBitmapByStream(String fileName, int maxResolutionX,
//			int maxResolutionY) {
//		Bitmap bitmapOrg = null;
//		Bitmap result = null;
//		try {
//
//			int sample = BitmapUtils.computeSampleSize(fileName,
//					maxResolutionX, maxResolutionY);
//			BitmapFactory.Options options = new BitmapFactory.Options();
//			options.inJustDecodeBounds = false;
//			options.inSampleSize = sample;
//			bitmapOrg = BitmapFactory.decodeFile(fileName, options);
//			// bitmapOrg = BitmapUtils.getBitmapByStream( is, WIDTH_IMAGE,
//			// HEIGHT_IMAGE);
//			// bitmapOrg = BitmapFactory.decodeStream(is, null, null);
//			if (bitmapOrg != null) {
//				int width = bitmapOrg.getWidth();
//				int height = bitmapOrg.getHeight();
//				float scaleWidth = ((float) maxResolutionX) / width;
//				float scaleHeight = ((float) maxResolutionY) / height;
//				Matrix matrix = new Matrix();
//				if (scaleWidth < 1 || scaleHeight < 1)
//					matrix.postScale(scaleWidth, scaleHeight);
//
//				result = Bitmap.createBitmap(bitmapOrg, 0, 0, width, height,
//						matrix, true);
//				// bitmapOrg.recycle(); FIXME we must check this case clearly because of FC issue (recycle bitmap)
//			}
//		} catch (Exception e) {
//			e.printStackTrace();
//			
//		}
//
//		return result;
//	}
//
//	public static int computeSampleSize(String path, int maxResolutionX,
//			int maxResolutionY) {
//		BitmapFactory.Options options = new BitmapFactory.Options();
//
//		try {
//			options.inJustDecodeBounds = true;
//			BitmapFactory.decodeFile(path, options);
//			int heightRatio = (int) Math.ceil(options.outHeight
//					/ maxResolutionY);
//			int widthRatio = (int) Math.ceil(options.outWidth / maxResolutionX);
//			Log.i(TAG, "org bitmap width=" + options.outWidth);
//			if (heightRatio > 1 && widthRatio > 1) {
//				if (heightRatio > widthRatio) {
//					options.inSampleSize = heightRatio;
//				} else {
//					// Width ratio is larger, scale according to it
//					options.inSampleSize = widthRatio;
//				}
//			}
//			Log.i(TAG, "Sample Size " + options.inSampleSize);
//
//		} catch (Exception e) {
//			Log.i(TAG, "Unexpected exception", e);
//		}
//
//		return options.inSampleSize;
//	}
//
//
//	public static int computeSampleSize(BitmapFactory.Options options,
//			int minSideLength, int maxNumOfPixels) {
//		int initialSize = computeInitialSampleSize(options, minSideLength,
//				maxNumOfPixels);
//
//		int roundedSize;
//		if (initialSize <= 8) {
//			roundedSize = 1;
//			while (roundedSize < initialSize) {
//				roundedSize <<= 1;
//			}
//		} else {
//			roundedSize = (initialSize + 7) / 8 * 8;
//		}
//
//		return roundedSize;
//	}
//
//	public static int computeInitialSampleSize(BitmapFactory.Options options,
//			int minSideLength, int maxNumOfPixels) {
//		double w = options.outWidth;
//		double h = options.outHeight;
//
//		int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : (int) Math
//				.ceil(Math.sqrt(w * h / maxNumOfPixels));
//		int upperBound = (minSideLength == UNCONSTRAINED) ? 128 : (int) Math
//				.min(Math.floor(w / minSideLength),
//						Math.floor(h / minSideLength));
//
//		if (upperBound < lowerBound) {
//			// return the larger one when there is no overlapping zone.
//			return lowerBound;
//		}
//
//		if ((maxNumOfPixels == UNCONSTRAINED)
//				&& (minSideLength == UNCONSTRAINED)) {
//			return 1;
//		} else if (minSideLength == UNCONSTRAINED) {
//			return lowerBound;
//		} else {
//			return upperBound;
//		}
//	}
//
//	protected static Bitmap scaledResize(Bitmap source, int newWidth,
//			int newHeight) {
//		return Bitmap.createScaledBitmap(source, newWidth, newHeight, false);
//	}
//
//	public static Bitmap matrixResize(Bitmap source, int originalWidth,
//			int orginalHeight, int newWidth, int newHeight) {
//		Matrix matrix = new Matrix();
//		matrix.postScale((float)newWidth / originalWidth, (float)newHeight / orginalHeight);
//		return Bitmap.createBitmap(source, 0, 0, originalWidth, orginalHeight,
//				matrix, true);
//	}
//	
//	/**
//	 * Resize bitmap to specific size by using Matrix
//	 * @param source bitmap want to resize.
//	 * @param newWidth new width.
//	 * @param newHeight new height
//	 * @return bitmap has been resized of null if an error occurred
//	 */
//	public static Bitmap matrixResize(Bitmap source, int newWidth, int newHeight) {
//		if (source == null)
//			return null;
//		Matrix matrix = new Matrix();
//		matrix.postScale((float)newWidth / source.getWidth(), (float)newHeight / source.getHeight());
//		return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
//				matrix, true);
//	}
//	
//	public static Bitmap calcBitmapSizeForAnimatedView(Bitmap bmpSource) {
//		if (bmpSource == null)
//			return null;
//		int orgWidth = bmpSource.getWidth();
//		int orgHeigh = bmpSource.getHeight();
//		int desireWidth = orgWidth;
//		int desireHeigh = orgHeigh;
//		Log.e(TAG, ">>> [calc new size] maxW=" + LayoutUtil.VIEW_EFFECT_MAX_WIDTH + " maxH=" + LayoutUtil.VIEW_EFFECT_MAX_HEIGH);
//		Log.e(TAG, ">>> [calc new size] minW=" + LayoutUtil.VIEW_EFFECT_MIN_WIDTH + " minH=" + LayoutUtil.VIEW_EFFECT_MIN_HEIGH);
//		Log.i(TAG, ">>> [calc new size] srcW=" + orgWidth + " srcH=" + orgHeigh);
//		if (orgWidth > LayoutUtil.VIEW_EFFECT_MAX_WIDTH
//				|| orgHeigh > LayoutUtil.VIEW_EFFECT_MAX_HEIGH
//				|| orgWidth > LayoutUtil.VIEW_EFFECT_MIN_WIDTH
//				|| orgHeigh > LayoutUtil.VIEW_EFFECT_MIN_HEIGH) {  
//			// image is larger than our animated view
//			if (orgWidth == orgHeigh) {
//				desireWidth = desireHeigh = LayoutUtil.VIEW_EFFECT_MAX_WIDTH;
//			} else {
//				if (orgWidth > orgHeigh) {
//					desireWidth = LayoutUtil.VIEW_EFFECT_MAX_WIDTH;
//					desireHeigh = (orgHeigh * desireWidth) / orgWidth;
//				} else {
//					desireHeigh = LayoutUtil.VIEW_EFFECT_MAX_HEIGH;
//					desireWidth = (orgWidth * desireHeigh) / orgHeigh;
//				}
//			}
//		}  else { 
//				// image is too smaller, let make it zoom to minimum size of our animated view 
//				if (orgWidth == orgHeigh) {
//					desireWidth = desireHeigh = LayoutUtil.VIEW_EFFECT_MIN_WIDTH;
//				} else {
//					if (orgWidth > orgHeigh) {
//						desireWidth = LayoutUtil.VIEW_EFFECT_MIN_WIDTH;
//						desireHeigh = (orgHeigh * desireWidth) / orgWidth;
//					} else {
//						desireHeigh = LayoutUtil.VIEW_EFFECT_MIN_HEIGH;
//						desireWidth = (orgWidth * desireHeigh) / orgHeigh;
//					}
//				}
////			}
//		}
//		Log.d(TAG, ">>> [calc new size] desireW=" + desireWidth + " desireH=" + desireHeigh);
//		return matrixResize(bmpSource, desireWidth, desireHeigh);
//	}
//
//	public static int[] getOriginalSize(String imagePath) {
//		if (TextUtils.isEmpty(imagePath))
//			return null;
//		
//		BitmapFactory.Options options = new BitmapFactory.Options();
//		int[] result = new int[2];
//		options.inJustDecodeBounds = true;
//		BitmapFactory.decodeFile(imagePath, options);
//		Log.d(TAG, ">>> original bitmap with w=" + options.outWidth + "  h="+options.outHeight);
//		result[0] = options.outWidth;
//		result[1] = options.outHeight;
//		return result;
//	}
//
//
//	public static int countSampleValue(int originalWidth, int originalHeight,
//			int newWidth, int newHeight) {
//		int sample = 1;
//
//		while ((originalWidth >> 1 > newWidth)
//				|| (originalHeight >> 1 > newHeight)) {
//			sample <<= 1;
//			originalWidth >>= 1;
//			originalHeight >>= 1;
//		}
//		Log.d(TAG, ">>> countSampleValue=" + sample);
//		return sample;
//	}
//	
//	public static void saveView2PNG(View view, String fileName) {
//		if (view == null) {
//			return;
//		}
//		View rootView = view.getRootView();
//		rootView.setDrawingCacheEnabled(true);
//		Bitmap viewBmp = Bitmap.createBitmap(rootView.getDrawingCache());
//		rootView.setDrawingCacheEnabled(false);
//
//		saveBitmap2PNG(viewBmp, fileName, false);
//	}
//
//	public static void saveBitmap2PNG(Bitmap bitmap, String fileName,
//			boolean doRecycle) {
//		if ((bitmap == null) || (bitmap.isRecycled())) {
//			return;
//		}
//		FileOutputStream outStream = null;
//		try {
//			String folder = (/*
//							 * DeviceStorageManager.isSupportPhoneStorage() ?
//							 * DeviceStorageManager.getPhoneStoragePath() :
//							 * DeviceStorageManager.getExternalStoragePath()
//							 */"") + "/"; // TODO need to fix this
//			String path = folder + fileName + "-" + bitmap.getHeight() + "X"
//					+ bitmap.getWidth() + ".png";
//
//			outStream = new FileOutputStream(path);
//			bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//			if (doRecycle) {
//				bitmap.recycle();
//			}
//			if (outStream != null) {
//				try {
//					outStream.close();
//				} catch (IOException ioe) {
//					ioe.printStackTrace();
//				}
//			}
//		} finally {
//			if (doRecycle) {
//				bitmap.recycle();
//			}
//			if (outStream != null)
//				try {
//					outStream.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//		}
//	}
	
}
